//
// Created by Strawberry on 2022/4/12.
//

#include "PageTable.h"

//TESTED
bool PageTable::access(long long int logical_loc) {
    if (in_memory(logical_loc)) {

        int page_number = Page::get_page_number(logical_loc);
        table[page_number]->page->access_flag = 0;

        //把table里其他的page的access_flag加1
        //记住要erase的page_number
        std::vector<int> to_be_erased;
        for (const auto &item : table){
            if(item.first != page_number){
                if(item.second != nullptr && item.second->page != nullptr){
                    item.second->page->access_flag++;
                }else{
                    //发现为null的数据 说明当前帧应该为空闲 尝试修复
                    to_be_erased.push_back(page_number);
                }
            }
        }
        //尝试修复
        for (const auto &item : to_be_erased){
            table.erase(item);
        }
        return true;
    } else {
        return false;
    }
}

//TESTED
bool PageTable::in_memory(long long int logical_loc) {
    int page_number = Page::get_page_number(logical_loc);
    return table.find(page_number) != table.end();
}

void PageTable::free() {
    //记住要erase的page_number
    std::vector<int> to_be_erased;
    for (const auto &item: table) {
        if(item.second != nullptr){
            item.second->is_free = true;
            if(item.second->page != nullptr){
                item.second->page->is_in_memory = false;
                int page_number = item.second->page->page_number;
                to_be_erased.push_back(page_number);
            }
            item.second->page = nullptr;
            g_all_free_frame.push_back(item.second);
        }
    }
    for (const auto &item : to_be_erased){
        table.erase(item);
    }
}

void PageTable::swap_out(Page *page) {
    page->is_in_memory = false;
    //放到交换区
    g_change_memory[page->logical_loc] = page;

    //释放它对应的帧
    table[page->page_number]->is_free = true;

    table[page->page_number]->page = nullptr;
    //加入到空闲帧list

    g_all_free_frame.push_back(table[page->page_number]);
    //从页表中删除该页

    table.erase(page->page_number);

}

void PageTable::swap_in(long long int logical_loc) {
    //在交换区找这个逻辑地址对应的帧，然后加入到页表
    //找到一个空闲帧，并指向该页
    auto frame = g_all_free_frame.front();
    frame->page = g_change_memory[logical_loc];
    frame->page->access_flag = 0;
    std::cout << "swap in: " << *(frame->page) << std::endl;
    
    frame->is_free = false;
    //放入页表
    table[frame->page->page_number] = frame;
}

void PageTable::lru() {
    //当前已有空闲帧 直接返回
    if (g_all_free_frame.size() > 0) {
        return;
    } else {
        int max_access = 0;
        auto to_be_swapped_out = table.begin()->second->page;
        for (const auto &item: table) {
            int now_access = item.second->page->access_flag;
            if (now_access > max_access) {
                max_access = now_access;
                to_be_swapped_out = item.second->page;
            }
        }
        if (to_be_swapped_out != nullptr) {
            std::cout << "swap out: " << *to_be_swapped_out << std::endl;
            swap_out(to_be_swapped_out);
        }
    }

}

//TESTED
void PageTable::show() {
    std::cout << "page_number\t\tframe_info" << std::endl;

    for (const auto &item : table){
        if(item.second != nullptr){
            std::cout<< item.first << "\t\t" << *item.second << std::endl;
        }else{
            std::cout<< item.first << "\t\tnull" << std::endl;
        }

    }
}
